
import Slot from './slot';

// constants
let appWidth = 1024;
let appHeight = 768;

let machineX = 0;
let machineY = 0;
let slotX = [22, 46, 70];
let slotY = [0, 0, 0];
let handlerX = 101;
let handlerY = 28;
let scale = 3;

// 每个数字对应在数字那张 png 文件中的位置
const slotWidth = 48;
const slotHeight = 96;
const slotMapper = {}
const fs =['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
fs.forEach((f, index) => {
  slotMapper[f] = {
    x : slotWidth * index,
    y : 0
  }
});

/** @type {PIXI.Sprite[]} */
let firstFigures = [null, null, null];
/** @type {PIXI.Sprite[]} */
let secondFigures = [null, null, null];
/** @type {PIXI.Graphics[]} */
let figureMasks = [null, null, null];

// 操作杆相关数据
let handler = {
  /** @type {PIXI.Sprite} */
  sprite : null,
  /** @type {PIXI.Graphics} */
  mask : null,
  /**
   * 操作杆的视觉状态.
   * 0 : 静止状态
   * 1 到 60 : 动作状态. 在动作状态时, 每一帧 +1. 60 后面一帧是 0, 静止.
   * 
   *  1-10 : 纹理 1
   * 11-20 : 纹理 2
   * 21-40 : 纹理 3
   * 41-50 : 纹理 2
   * 51-60 : 纹理 1
   */
  state : 0,
  /** @type {PIXI.Rectangle} */
  zone : null,
  /**
   * 是否鼠标悬停
   */
  hover : false,

  trigger : function () {
    if (this.state) return;
    this.state = 1;
  }
};

class SnowButton {
  /** @type {PIXI.Sprite} */
  sprite = null;
  /** @type {PIXI.Graphics} */
  mask = null;
  /** @type {PIXI.Rectangle} */
  zone = null;
  pos = 0;

  x = 0;
  y = 87;
  /**
   * 0 : 启动状态, 可以按
   * 1 : 关闭状态
   */
  state = 0;
  /**
   * 是否鼠标悬停
   */
  hover = false;

  constructor (pos) {
    this.pos = pos;

    switch (pos) {
      case 0: this.x = 22; break;
      case 1: this.x = 46; break;
      case 2: this.x = 70; break;
    }
  }

  /**
   * 启动, 变亮
   */
  release () {
    this.state = 0;
  }

  /**
   * 变暗, 对应的老虎机槽减速
   */
  trigger () {
    this.state = 1;
  }
}

let snowButtons = [new SnowButton(0), new SnowButton(1), new SnowButton(2)];

class Painter {
  constructor (params) {
    const { PIXI, ticker, assetPath : imagePath, env, events } = params;

    this.PIXI = PIXI;
    this.ticker = ticker;
    this.env = env;
    this.events = events;

    let type = "WebGL";
    if (!PIXI.utils.isWebGLSupported()) {
      type = "canvas";
    }

    let app = this.app = new PIXI.Application({width: appWidth, height: appHeight, type});
    app.renderer.backgroundColor = 0x061639;

    PIXI.loader
      .add("machine", imagePath('img/machine.png'))
      .add("figures", imagePath('img/figures.png'))
      .add("handler", imagePath('img/handler.png'))
      .add("buttons", imagePath('img/buttons.png'))
      .load(() => {this.setup();});

    // 原生 DOM 操作
    document.getElementById("main").appendChild(app.view);
  }

  setup () {
    const { PIXI, app } = this;

    let tx = PIXI.loader.resources["machine"].texture;
    tx.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;

    let machine = new PIXI.Sprite(tx);
    machineX = machine.x = (appWidth - scale * tx.width) / 2;
    machineY = machine.y = (appHeight - scale * tx.height) / 2 - 50;
    machine.scale.x = machine.scale.y = scale;

    app.stage.addChild(machine);

    slotX[0] = machineX + 22 * scale;
    slotX[1] = machineX + 46 * scale;
    slotX[2] = machineX + 70 * scale;
    slotY[0] = slotY[1] = slotY[2] = machineY + 37 * scale;

    for (let i = 0; i < figureMasks.length; i++) {
      let mask = new PIXI.Graphics();
      mask.beginFill(0xFFFFFF);
      mask.drawRect(slotX[i], slotY[i], slotWidth, slotHeight);
      mask.endFill();
      figureMasks[i] = mask;
    }

    // 杆子部分
    {
      tx = PIXI.loader.resources["handler"].texture;
      tx.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
      handlerX = handlerX * scale + machineX;
      handlerY = handlerY * scale + machineY;
      handler.mask = new PIXI.Graphics();
      handler.mask.beginFill(0xFFFFFF);
      handler.mask.drawRect(handlerX, handlerY, 16 * scale, 80 * scale);
      handler.mask.endFill();
      handler.zone = new PIXI.Rectangle(handlerX, handlerY, 16 * scale, 80 * scale);
      handler.sprite = new PIXI.Sprite(tx);
      handler.sprite.mask = handler.mask;
      handler.sprite.x = handlerX;
      handler.sprite.y = handlerY;
      handler.sprite.scale.x = scale;
      handler.sprite.scale.y = scale;
      app.stage.addChild(handler.sprite);
    }

    // 按钮部分
    {
      tx = PIXI.loader.resources["buttons"].texture;
      tx.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
      snowButtons.forEach((btn) => {
        btn.x = btn.x * scale + machineX;
        btn.y = btn.y * scale + machineY;
        btn.mask = new PIXI.Graphics();
        btn.mask.beginFill(0xFFFFFF);
        btn.mask.drawRect(btn.x, btn.y, 16 * scale, 16 * scale);
        btn.mask.endFill();
        btn.zone = new PIXI.Rectangle(btn.x, btn.y, 16 * scale, 16 * scale);
        btn.sprite = new PIXI.Sprite(tx);
        btn.sprite.mask = btn.mask;
        btn.sprite.x = btn.x;
        btn.sprite.y = btn.y;
        btn.sprite.scale.x = scale;
        btn.sprite.scale.y = scale;
        btn.sprite.zIndex = 1;
        app.stage.addChild(btn.sprite);
        btn.state = 1;
      })
    }

    // 这里介绍如何截取纹理的一部分来显示
    // 使用蒙版
    this.draw();
    
    // 最后操作
    app.ticker.add(delta => {
      this.ticker(); // callback
      this.draw();
    });

    // 添加 Listener
    app.view.onclick = (event) => {
      const x = event.offsetX, y = event.offsetY;
      if (handler.zone.contains(x, y)) {
        // 全部启动
        this.events.machineBegin();
        return;
      }

      // 按钮
      snowButtons.forEach((btn) => {
        if (btn.zone.contains(x, y) && btn.state == 0) {
          this.events.machineEnd(btn.pos);
        }
      });
    }
    app.view.onmousemove = function (event) {
      const x = event.offsetX, y = event.offsetY;
      handler.hover = handler.zone.contains(x, y);

      snowButtons.forEach((btn) => {
        btn.hover = btn.zone.contains(x, y);
      })
    }
    app.view.onmouseout = function (event) {
      handler.hover = false;
      snowButtons.forEach((btn) => {btn.hover = false;});
    }
  }

  draw () {
    const { PIXI, app, env } = this;

    let tx = PIXI.loader.resources["figures"].texture;

    // 画数字
    for (let i = 0; i < 3; i ++) {
      let firstFigure = firstFigures[i];
      let secondFigure = secondFigures[i];
      let mask = figureMasks[i];
      if (!firstFigure) {
        firstFigures[i] = firstFigure = new PIXI.Sprite(tx);
        firstFigure.zIndex = 1;
        firstFigure.mask = mask; // 遮罩使用的是绝对位置
        app.stage.addChild(firstFigure);
      }
      if (!secondFigure) {
        secondFigures[i] = secondFigure = new PIXI.Sprite(tx);
        secondFigure.zIndex = 1;
        secondFigure.mask = mask;
        app.stage.addChild(secondFigure);
      }

      /** @type {Slot} */
      let slot = env.slots[i];
      // firstFigure 和 secondFigure 的位置
      let currentFigure = slot.currentFigure();
      let nextFigure = slot.nextFigure();
      firstFigure.x = slotX[i] - slotMapper[currentFigure].x;
      firstFigure.y = slotY[i] - slotMapper[currentFigure].y - slotHeight * slot.offset;
      secondFigure.x = slotX[i] - slotMapper[nextFigure].x;
      secondFigure.y = slotY[i] - slotMapper[nextFigure].y - slotHeight * slot.offset + slotHeight;
    }

    // 画杆子
    {
      if (handler.state) {
        handler.state++;
        if (handler.state >= 60) {
          handler.state = 0;
          snowButtons.forEach((btn) => btn.release());
        }
      }

      let chosen;
      if ((handler.state > 10 && handler.state <= 20) || (handler.state > 40 && handler.state <= 50)) {
        chosen = 1;
      } else if (handler.state > 20 && handler.state <= 40) {
        chosen = 2;
      } else {
        chosen = (handler.state == 0 && handler.hover) ? 3 : 0;
      }

      handler.sprite.x = handlerX - chosen * 16 * scale;
    }

    // 画按钮
    {
      snowButtons.forEach((btn) => {
        let chosen = btn.state ? 1 : (btn.hover ? 2 : 0);
        btn.sprite.x = btn.x - chosen * 16 * scale;
      });
    }
  }

  // 按了拉杆
  handlerClick () {
    handler.trigger();
  }

  // 按了按钮 0,1,2
  handlerStop (index) {
    snowButtons.forEach((btn) => {
      if (btn.pos === index && btn.state == 0) {
        btn.trigger();
      }
    });
  }
}

export default Painter;
